<template>
  <el-form
      ref="form"
      v-if="model"
      :validate-on-rule-change="false"
      :model="model"
      :rules="rules"
      v-bind="$attrs"
  >
    <template v-for="(item, index) in options" :key="index">
      <!--单项的输入框-->
      <el-form-item
          v-if="!item.children || !item.children!.length"
          :prop="item.prop"
          :label="item.label"
      >
        <component
            v-if="item.type !== 'upload' && item.type !== 'editor'"
            :placeholder="item.placeholder"
            v-bind="item.attrs"
            :is="`el-${item.type}`"
            v-model="model[item.prop!]"
        ></component>
        <el-upload
            v-if="item.type === 'upload'"
            v-bind="item.uploadAttrs"
            :on-preview="onPreview"
            :on-remove="onRemove"
            :on-success="onSuccess"
            :on-error="onError"
            :on-progress="onProgress"
            :on-change="onChange"
            :before-upload="beforeUpload"
            :before-remove="beforeRemove"
            :http-request="httpRequest"
            :on-exceed="onExceed"
        >
          <slot name="uploadArea"></slot>
          <slot name="uploadTip"></slot>
        </el-upload>
        <div id="editor" v-if="item.type === 'editor'"></div>
      </el-form-item>
      <!--有子项的表单项-->
      <el-form-item
          v-if="item.children && item.children.length"
          :prop="item.prop"
          :label="item.label"
      >
        <component
            :placeholder="item.placeholder"
            v-bind="item.attrs"
            :is="`el-${item.type}`"
            v-model="model[item.prop!]"
        >
          <component
              v-for="(child, i) in item.children"
              :key="i"
              :is="`el-${child.type}`"
              :label="child.label"
              :value="child.value"
          ></component>
        </component>
      </el-form-item>
    </template>
    <el-form-item>
      <slot name="action" :form="form" :model="model"></slot>
    </el-form-item>
  </el-form>
</template>

<script lang='ts' setup>
import {PropType, ref, onMounted, watch, nextTick} from 'vue'
import {FormInstance, FormOptions} from './types/types'
import cloneDeep from 'lodash/cloneDeep' //分模块引入，支持tree-shaking
import E from 'wangeditor' //富文本编辑器 第三方库


let emits = defineEmits(['on-preview', 'on-remove', 'on-success', 'on-error', 'on-progress', 'on-change', 'before-upload', 'before-remove', 'on-exceed'])

let props = defineProps({
  // 表单的配置项
  options: {
    type: Array as PropType<FormOptions[]>,
    required: true
  },
  // 用户自定义上传方法
  httpRequest: {
    type: Function
  }
})
console.log('props',props)

let model = ref<any>(null)
let rules = ref<any>(null)

let form = ref<FormInstance | null>()
let edit = ref()

// 初始化表单
let initForm = () => {
  if (props.options && props.options.length) {
    let m: any = {}
    let r: any = {}

    console.log('props.options', props.options)

    props.options.map((item: FormOptions) => {
      m[item.prop!] = item.value //处理成{username:'',password:''}的格式
      r[item.prop!] = item.rules
      if (item.type === 'editor') {
        // 初始化富文本
        nextTick(() => {
          if (document.getElementById('editor')) {
            const editor = new E('#editor')
            editor.config.placeholder = item.placeholder!
            editor.create()
            // 初始化富文本的内容
            editor.txt.html(item.value)
            editor.config.onchange = (newHtml: string) => {
              model.value[item.prop!] = newHtml
            }
            edit.value = editor
          }
        })
      }
    })
    model.value = cloneDeep(m) //model和rules都是引用数据类型，需要深拷贝一份（这边用来处理数据）
    rules.value = cloneDeep(r)
  }
}

// 重置表单
let resetFields = () => {
  // 重置element-plus的表单
  form.value!.resetFields()
  // 重置富文本编辑器的内容
  // 获取到富文本的配置项
  if (props.options && props.options.length) {
    let editorItem = props.options.find(item => item.type === 'editor')!
    edit.value.txt.html(editorItem.value)
  }
}
// 表单验证方法
let validate = () => {
  return form.value!.validate
}
// 获取表单数据
let getFormData = () => {
  return model.value
}

// setup默认是关闭的，这里用defineExpose对外暴露方法
defineExpose({
  resetFields,
  validate,
  getFormData
})

onMounted(() => {
  initForm()
})
// 监听父组件传递进来的options
watch(() => props.options, () => {
  initForm()
}, {deep: true})


// 上传组件的所有方法
let onPreview = (file: File) => {
  emits('on-preview', file)
}
let onRemove = (file: File, fileList: FileList) => {
  emits('on-remove', {file, fileList})
}
let onSuccess = (response: any, file: File, fileList: FileList) => {
  // 上传图片成功 给表单上传项赋值
  let uploadItem = props.options.find(item => item.type === 'upload')!
  model.value[uploadItem.prop!] = {response, file, fileList}
  emits('on-success', {response, file, fileList})
}
let onError = (err: any, file: File, fileList: FileList) => {
  emits('on-error', {err, file, fileList,})
}
let onProgress = (event: any, file: File, fileList: FileList) => {
  emits('on-progress', {event, file, fileList})
}
let onChange = (file: File, fileList: FileList) => {
  emits('on-change', {file, fileList})
}
let beforeUpload = (file: File) => {
  emits('before-upload', file)
}
let beforeRemove = (file: File, fileList: FileList) => {
  emits('before-remove', {file, fileList})
}
let onExceed = (files: File, fileList: FileList) => {
  emits('on-exceed', {files, fileList})
}


</script>

<style lang='scss' scoped>
</style>
